﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Estimate.Common.Entity;
using Estimate.Common.DBFieldTypes;
using Estimate.Common.Repository;
using Estimate.Common.Estimate;
using Estimate.Common.Estimate.EstimateValue;
using System.Runtime.Serialization;
using Newtonsoft.Json;

namespace Estimate.Reports
{
    /// <summary>
    /// 基础排名类
    /// </summary>
    public class ReportScore
    {
        /// <summary>
        /// 需要计算排名的城镇
        /// </summary> 
       public  Dictionary<string, string> CityCodes;

       /// <summary>
       /// 需要计算排名的预报员的排班表
       /// </summary> 
       public List<ScheduleEntity> IndividualSchedules;

       /// <summary>
       /// 存储晴雨检验得分
       /// 06、16时 
       /// 外层字典key:cityCode或forecast,内层字典key:ForeSpanType
       /// </summary>
       public Dictionary<string, Dictionary<ForeSpanType, WaterScore>> WaterfallAmountScore=new Dictionary<string,Dictionary<ForeSpanType,WaterScore>>() ;

        /// <summary>
       /// 存储最高气温得分
        /// 06、16时
       /// 外层字典key:cityCode或forecast,内层字典key:ForeSpanType
        /// </summary>
        public Dictionary<string, Dictionary<ForeSpanType, TempScore>> MaxTempScore=new Dictionary<string,Dictionary<ForeSpanType,TempScore>>() ;
       
        /// <summary>
        /// 存储最低气温得分
        /// 06、16时
        /// 外层字典key:cityCode或forecast,内层字典key:ForeSpanType
        /// </summary>
        public Dictionary<string, Dictionary<ForeSpanType, TempScore>> MinTempScore =new Dictionary<string,Dictionary<ForeSpanType,TempScore>>();

        /// <summary>
        /// 存储预报员晴雨检验样本记录数
        /// </summary>
        public Dictionary<string, Dictionary<string, int>> IndividualRecordCount = new Dictionary<string, Dictionary<string, int>>();

        ForeRepository DataProvider;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider">获取基础数据的对象</param>
        /// <param name="cityCodes">需要计算排名的城镇</param>
        public ReportScore(ForeRepository provider, Dictionary<string, string> cityCodes)
        {
            DataProvider = provider;
            CityCodes = cityCodes;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider">获取基础数据的对象</param>
        /// <param name="cityCodes">需要计算排名的预报员排班表</param>
        public ReportScore(ForeRepository provider, List<ScheduleEntity> individualSchedules)
        {
            DataProvider = provider;
            IndividualSchedules = individualSchedules;
        }

        /// <summary>
        /// 初始化存储得分的Dictionary
        /// </summary>
        /// <param name="Spans"></param>
        private void InitScore(ForeSpanType[] Spans)
        {
            if (CityCodes != null)
            {
                foreach (string city in CityCodes.Values)
                {
                    WaterfallAmountScore.Add(city, new Dictionary<ForeSpanType, WaterScore>(Spans.Length));
                    MaxTempScore.Add(city, new Dictionary<ForeSpanType, TempScore>(Spans.Length));
                    MinTempScore.Add(city, new Dictionary<ForeSpanType, TempScore>(Spans.Length));
                    foreach (ForeSpanType span in Spans)
                    {
                        WaterfallAmountScore[city].Add(span, new WaterScore());
                        MaxTempScore[city].Add(span, new TempScore());
                        MinTempScore[city].Add(span, new TempScore());
                    }

                    //_individualRecordCount.Add(city, new Dictionary<string, int>());
                }
            }

            else if (IndividualSchedules != null)
            {
                foreach (ScheduleEntity schedule in IndividualSchedules)
                {
                    //key格式为"站点号_预报员编号;站点名称"
                    string key = GlobalFunction.AssemblyForecastNum(schedule);

                    if (WaterfallAmountScore.ContainsKey(key)) continue;

                    WaterfallAmountScore.Add(key, new Dictionary<ForeSpanType, WaterScore>(Spans.Length));
                    MaxTempScore.Add(key, new Dictionary<ForeSpanType, TempScore>(Spans.Length));
                    MinTempScore.Add(key, new Dictionary<ForeSpanType, TempScore>(Spans.Length));
                    foreach (ForeSpanType span in Spans)
                    {
                        WaterfallAmountScore[key].Add(span, new WaterScore());
                        MaxTempScore[key].Add(span, new TempScore());
                        MinTempScore[key].Add(span, new TempScore());
                    }

                    IndividualRecordCount.Add(key, new Dictionary<string, int>());
                }
            }

        }

        private void Clear()
        {
            
            WaterfallAmountScore.Clear();
            MaxTempScore.Clear();
            MinTempScore.Clear();
            WaterfallAmountScore.Clear();
            MaxTempScore.Clear();
            MinTempScore.Clear();
            IndividualRecordCount.Clear();
        }

        //public void SetIndividualRecordCount(string city, DateTime date, ForeClockType clock, ForeSpanType span, int count)
        //{
        //    string[] span_range = span.ToString().Replace("FD", "").Split(new char[] { '_' });
        //    if (Convert.ToInt32(span_range[1]) - Convert.ToInt32(span_range[0]) == 24)
        //    {
        //        string key = date.ToString("yyyyMMdd") + clock.ToString();
        //        if (!_individualRecordCount[city].ContainsKey(key))
        //            _individualRecordCount[city].Add(key, count);
        //        else
        //            _individualRecordCount[city][key] += count;
        //    }
        //}

        //public void PrepareData(DateTime beginDate, DateTime endDate, ForeSemiType semitype)
        //{
        //    SendpointToClock parser = new SendpointToClock();
        //    ForeSpanType[] Spans = new ForeSpanType[] { ForeSpanType.FD00_24, ForeSpanType.FD24_48, ForeSpanType.FD48_72, ForeSpanType.FD72_96, ForeSpanType.FD96_120 };
        //    ForeSendpointType[] sendpoints = new ForeSendpointType[] { ForeSendpointType.H06, ForeSendpointType.H16 };
        //    ForeClockType[] clocks = parser.GetClockArrayWithSendPointArray(sendpoints);

        //    PrepareData(beginDate, endDate, clocks, Spans, sendpoints, semitype);
        //}

        //public void PrepareData(DateTime beginDate, DateTime endDate,ForeSpanType span, ForeSemiType semitype)
        //{
        //    SendpointToClock parser = new SendpointToClock();
        //    ForeSpanType[] Spans = new ForeSpanType[] { span };
        //    ForeSendpointType[] sendpoints = new ForeSendpointType[] { ForeSendpointType.H06, ForeSendpointType.H16 };
        //    ForeClockType[] clocks = parser.GetClockArrayWithSendPointArray(sendpoints);

        //    PrepareData(beginDate, endDate, clocks, Spans, sendpoints, semitype);
        //}

        /// <summary>
        /// 准备数据
        /// </summary>
        /// <param name="beginDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <param name="realtype">实况类型</param>
        /// <param name="sendpoints">发报时刻</param>
        public void PrepareData(DateTime beginDate, DateTime endDate,ForeClockType[] clocks, ForeSpanType[] Spans,ForeSendpointType[] sendpoints,ForeSemiType semitype)
        {
            ForeEntity[] semis;

            WaterScoreCalculate waterCalculate = new WaterScoreCalculate();
            TempScoreCalculate tempCalculate = new TempScoreCalculate();

            Clear();
            InitScore(Spans);//初始化

            foreach (ForeSpanType span in Spans)
            {
                //计算晴雨
                if (semitype == ForeSemiType.Manual)
                {
                    semis = DataProvider.InquerySemiWithDateRange(beginDate, endDate, clocks, span, sendpoints, ForeFactorType.wth, semitype, true);
                   
                    foreach (ForeEntity semi in semis)
                    {
                        if (CityCodes != null)
                            waterCalculate.CalculateWaterfallAmounBySemiString(WaterfallAmountScore, semi, span, CityCodes);
                        else if (IndividualSchedules != null)
                            waterCalculate.CalculateWaterfallAmounBySemiString(WaterfallAmountScore, IndividualRecordCount, semi, span, IndividualSchedules);
                    }
                }
                else
                {
                    ForeSpanType firstSpan, lastSpan;
                    ForeSpanTypeTools.Get12Spans(span, out firstSpan, out lastSpan);
                    semis = DataProvider.InquerySemiWithDateRange(beginDate, endDate, clocks, firstSpan, sendpoints, ForeFactorType.wth, semitype, true);
                    foreach (ForeEntity semi in semis)
                    {
                        if (CityCodes != null)
                            waterCalculate.CalculateWaterfallAmounBySemiString(WaterfallAmountScore, semi, span, CityCodes);
                        else if (IndividualSchedules != null)
                            waterCalculate.CalculateWaterfallAmounBySemiString(WaterfallAmountScore, IndividualRecordCount, semi, span, IndividualSchedules);
                    }
                    semis = DataProvider.InquerySemiWithDateRange(beginDate, endDate, clocks, lastSpan, sendpoints, ForeFactorType.wth, semitype, true);
                    foreach (ForeEntity semi in semis)
                    {
                        if (CityCodes != null)
                            waterCalculate.CalculateWaterfallAmounBySemiString(WaterfallAmountScore, semi, span, CityCodes);
                        else if (IndividualSchedules != null)
                            waterCalculate.CalculateWaterfallAmounBySemiString(WaterfallAmountScore, null, semi, span, IndividualSchedules);
                    }
                }


                //计算最高温
                semis = DataProvider.InquerySemiWithDateRange(beginDate, endDate, clocks, span, sendpoints, ForeFactorType.maxt, semitype, true);
                foreach (ForeEntity semi in semis)
                {
                    if (CityCodes != null)
                        tempCalculate.CulculateTemperatureScoreBySemiString(MaxTempScore, semi, span, CityCodes);
                    else if (IndividualSchedules != null)
                        tempCalculate.CulculateTemperatureScoreBySemiString(MaxTempScore, semi, span, IndividualSchedules);
                }


                //计算最低温
                semis = DataProvider.InquerySemiWithDateRange(beginDate, endDate, clocks, span, sendpoints, ForeFactorType.mint, semitype, true);
                foreach (ForeEntity semi in semis)
                {
                    if (CityCodes != null)
                        tempCalculate.CulculateTemperatureScoreBySemiString(MinTempScore, semi, span, CityCodes);
                    else if (IndividualSchedules != null)
                        tempCalculate.CulculateTemperatureScoreBySemiString(MinTempScore, semi, span, IndividualSchedules);
                }
            }

        }

      
        /// <summary>
        /// 计算积分
        /// 返回结果为嵌套的Dictionary 
        /// key1:城市名;key2:积分类型，包括wth,temp,FD24_Water_Skill,FD24_MaxT_Skill,FD24_MinT_Skill,MixPC,MixMaxTt2,MixMinTt2
        /// </summary>
        /// <param name="standardReport">用来比较的标准数据</param>
        /// <returns></returns>
        public Dictionary<string, Dictionary<string, object>> CalculateResult(ReportScore standardReport)
        {
            Dictionary<string, Dictionary<string, object>> result = new Dictionary<string, Dictionary<string, object>>();
           
            if (CityCodes != null)
            {
                foreach (KeyValuePair<string, string> city in CityCodes)
                    SetResult(result, city.Key, city.Value, standardReport);
            }
            else if (IndividualSchedules != null)
            {
                foreach (string key in WaterfallAmountScore.Keys)
                    SetResult(result, key, key, standardReport);
            }

            return result;

        }

        private void SetResult(Dictionary<string, Dictionary<string, object>> result, string resultKey, string valueKey, ReportScore standardReport)
        {
            result.Add(resultKey, new Dictionary<string, object>());
            result[resultKey].Add("wth", WaterfallAmountScore[valueKey]);

            result[resultKey].Add("max", MaxTempScore[valueKey]);
            result[resultKey].Add("min", MinTempScore[valueKey]);

            ///  24小时晴雨技巧
            ///  06时
            float ts = WaterfallAmountScore[valueKey][ForeSpanType.FD00_24].PC;
            float standardTS = standardReport.WaterfallAmountScore[valueKey][ForeSpanType.FD00_24].PC;
            double Water_Skill = 0.0;
            if (standardTS != 101.0f && ts != 101.0f)
            {
                if (standardTS != 100)
                    Water_Skill = (ts - standardTS) / (100f - standardTS);
                else
                    Water_Skill = 0;
            }
            result[resultKey].Add("FD24_Water_Skill", Water_Skill);

            //FD24计算最高温
            double MaxT_Skill = 0.0;
            ts = MaxTempScore[valueKey][ForeSpanType.FD00_24].Tt2;
            standardTS = standardReport.MaxTempScore[valueKey][ForeSpanType.FD00_24].Tt2;
            if (ts != 0f && standardTS != 0f)
                MaxT_Skill = (ts - standardTS) / standardTS;
            result[resultKey].Add("FD24_MaxT_Skill", MaxT_Skill);

            //FD24计算最低温
            double Min_Skill = 0.0;
            ts = MinTempScore[valueKey][ForeSpanType.FD00_24].Tt2;
            standardTS = standardReport.MinTempScore[valueKey][ForeSpanType.FD00_24].Tt2;
            if (ts != 0f && standardTS != 0f)
                Min_Skill = (ts - standardTS) / standardTS;
            result[resultKey].Add("FD24_MinT_Skill", Min_Skill);


            double MixPC = -1;
            if (MixPC == -1)
            {
                MixPC = 0;

                MixPC += WaterfallAmountScore[valueKey][ForeSpanType.FD00_24].PC * 10;
                MixPC += WaterfallAmountScore[valueKey][ForeSpanType.FD24_48].PC * 8;
                MixPC += WaterfallAmountScore[valueKey][ForeSpanType.FD48_72].PC * 6;
                MixPC += WaterfallAmountScore[valueKey][ForeSpanType.FD72_96].PC * 2;
                MixPC += WaterfallAmountScore[valueKey][ForeSpanType.FD96_120].PC * 1;

                MixPC /= 27;
            }
            result[resultKey].Add("MixPC", MixPC);


            double MixMaxTt2 = -1;
            if (MixMaxTt2 == -1)
            {
                MixMaxTt2 = 0;

                MixMaxTt2 += MaxTempScore[valueKey][ForeSpanType.FD00_24].Tt2 * 10;
                MixMaxTt2 += MaxTempScore[valueKey][ForeSpanType.FD24_48].Tt2 * 8;
                MixMaxTt2 += MaxTempScore[valueKey][ForeSpanType.FD48_72].Tt2 * 6;
                MixMaxTt2 += MaxTempScore[valueKey][ForeSpanType.FD72_96].Tt2 * 2;
                MixMaxTt2 += MaxTempScore[valueKey][ForeSpanType.FD96_120].Tt2 * 1;

                MixMaxTt2 /= 27;
            }
            result[resultKey].Add("MixMaxTt2", MixMaxTt2);


            double MixMinTt2 = -1;
            if (MixMinTt2 == -1)
            {
                MixMinTt2 = 0;

                MixMinTt2 += MinTempScore[valueKey][ForeSpanType.FD00_24].Tt2 * 10;
                MixMinTt2 += MinTempScore[valueKey][ForeSpanType.FD24_48].Tt2 * 8;
                MixMinTt2 += MinTempScore[valueKey][ForeSpanType.FD48_72].Tt2 * 6;
                MixMinTt2 += MinTempScore[valueKey][ForeSpanType.FD72_96].Tt2 * 2;
                MixMinTt2 += MinTempScore[valueKey][ForeSpanType.FD96_120].Tt2 * 1;

                MixMinTt2 /= 27;
            }
            result[resultKey].Add("MixMinTt2", MixMinTt2);

            result[resultKey].Add("SumOrder", 0.0);

            result[resultKey].Add("Order", 0);

            //_individualRecordCount加上standardReport的_individualRecordCount是否合理？？？？？
            if (standardReport.IndividualRecordCount != null && standardReport.IndividualRecordCount.Count > 0)
            {
                foreach (KeyValuePair<string, int> pair in standardReport.IndividualRecordCount[valueKey])
                {
                    if (IndividualRecordCount[valueKey].ContainsKey(pair.Key))
                        IndividualRecordCount[valueKey][pair.Key] += pair.Value;
                    else
                        IndividualRecordCount[valueKey].Add(pair.Key, pair.Value);
                }
            }

            int RecordCount = 0;

            if (IndividualRecordCount != null && IndividualRecordCount.Count > 0)
            {
                foreach (KeyValuePair<string, int> pair in IndividualRecordCount[valueKey])
                    RecordCount += pair.Value;
            }
            result[resultKey].Add("RecordCount", RecordCount);
        }


    }
}
